360度测试:KAFKA会丢数据么?其高可用是否满足需求?
微信公众号排版或有问题,请点击查看原文获得更好体验
请仔细了解这张图,尤其注意有标志的几个关注点。我们会不止一次回到这张图上
背景
Kafka 到底能够应用在高可用的业务上?官方给出的答案是肯定的,最新版,已经支持消息队列的事务,但我们对其性能是有疑问的。
Kafka 根据配置的 ACK 级别,其性能表现将特别大,为了找到其适用场景,特做此测试,以便应用 kafka 时能够灵活应对。
测试过程还探讨了许多丢消息的场景。相对于大多数仅仅针对 kafka 集群本身的测试,本测试还介绍了丢消息的业务场景。整个方案应该是一个整体,才能够达到最高级别的高可用,不因该区别对待。
测试目标
集群高可用,以及需要满足高可用时需要的最小集群大小和相关配置以及限制等
消息不丢失,以及为了满足消息不丢失需要的配置和约定等
测试环境
broker:
3台机器
8 core
16G
1T SSD
Centos 6.8
kafka_2.12-0.10.2.0
broker jvm参数配置:Xms=8G Xmx=8G
client:
8 core
16G
Centos 6.8
测试场景
集群高可靠性配置:
zookeeper.connection.timeout.ms=15000
zookeeper.session.timeout.ms=15000
default.replication.factor=3
num.partitions=6
min.insync.replicas=2
unclean.leader.election.enable=false
log.flush.interval.ms=1000
ack
acks= all
retries = 3
request.timeout.ms=5000
消息大小:1024byte
failover 测试
测试方法
下线一个节点,测试故障的恢复时间和故障期间的服务水平
测试过程
将 replica.lag.time.max.ms 从 10s 调整为 60s(延长时间方便观察),然后 kill Broker 0,挑选 3 个 partition,观察 ISR 变化如下:
其中,第二 / 三阶段入队成功率受损:
第二阶段期间,Partition 96/97/98 均无法写入,入队成功率成功率下降至 0%。
第三阶段期间,Partition 96 可继续写入,但 Partition 97/98 无法写入,因为写入要等 Broker 0 回 ack,但 Broker 0 已 kill,入队成功率下降至 33%。
而实际观察,第二 / 三阶段期间完全没吞吐,原因是压测工具不断报连接失败,停止了写入。
原因分析
Kafka Broker leader 是通过 Controller 选举出来的,ISR 列表是 leader 维护的。
前者的的租约是 Controller 定义的,后者的租约是 Broker 配置 replica.lag.time.max.ms 指定的。
所以,第二阶段持续时间较短,是 Controller 的租约时间决定的,第三阶段持续时间较长,是 replica.lag.time.max.ms 决定的。
当 Broker 0 被 kill 时,前者影响本来 Broker 0 是 leader 的 1/3 partitions 的入队成功率,后者影响 Broker 0 作为 follower 的 2/3 partitions 的入队成功率。
HA 结论
kafka 在 failover 期间,会有大约 10 秒的不可用时间,该时间由 replica.lag.time.max.ms 决定。因此应用程序需要处理此种情况下的异常信息,设置合理的重试次数和退避算法。
压力测试
测试方法
测试脚本:
./kafka-producer-perf-test.sh --topic test003 --num-records 1000000 --record-size 1024 --throughput -1 --producer.config ../config/producer.properties
测试结果
不限制并发吞吐量
[root@l-monitor-logstash2.pub.prod.aws.dm bin]# time ./kafka-producer-perf-test.sh --topic ack001 --num-records 1000000 --record-size 1024 --throughput -1 --producer.config ../config/producer.properties
[2017-09-14 2157,543] WARN Error while fetching metadata with correlation id 1 : {ack001=LEADER_NOT_AVAILABLE} (org.apache.kafka.clients.NetworkClient)
81112 records sent, 16219.2 records/sec (15.84 MB/sec), 1416.2 ms avg latency, 1779.0 max latency.
92070 records sent, 18414.0 records/sec (17.98 MB/sec), 1671.7 ms avg latency, 1821.0 max latency.
91860 records sent, 18368.3 records/sec (17.94 MB/sec), 1670.3 ms avg latency, 1958.0 max latency.
91470 records sent, 18294.0 records/sec (17.87 MB/sec), 1672.3 ms avg latency, 2038.0 max latency.
91050 records sent, 18202.7 records/sec (17.78 MB/sec), 1678.9 ms avg latency, 2158.0 max latency.
92670 records sent, 18534.0 records/sec (18.10 MB/sec), 1657.6 ms avg latency, 2223.0 max latency.
89040 records sent, 17808.0 records/sec (17.39 MB/sec), 1715.0 ms avg latency, 2481.0 max latency.
86370 records sent, 17274.0 records/sec (16.87 MB/sec), 1767.5 ms avg latency, 2704.0 max latency.
91290 records sent, 18254.3 records/sec (17.83 MB/sec), 1670.2 ms avg latency, 2553.0 max latency.
92220 records sent, 18444.0 records/sec (18.01 MB/sec), 1658.1 ms avg latency, 2626.0 max latency.
90240 records sent, 18048.0 records/sec (17.63 MB/sec), 1669.9 ms avg latency, 2733.0 max latency.
1000000 records sent, 17671.591150 records/sec (17.26 MB/sec), 1670.61 ms avg latency, 2764.00 ms max latency, 1544 ms 50th, 2649 ms 95th, 2722 ms 99th, 2753 ms 99.9th.
real 0m57.409s
user 0m14.544s
sys 0m2.072s
限制吞吐量 1w
[root@l-monitor-logstash2.pub.prod.aws.dm bin]# time ./kafka-producer-perf-test.sh --topic ack003 --num-records 1000000 --record-size 1024 --throughput 10000 --producer.config ../config/producer.properties
[2017-09-15 1053,184] WARN Error while fetching metadata with correlation id 1 : {ack003=LEADER_NOT_AVAILABLE} (org.apache.kafka.clients.NetworkClient)
[2017-09-15 1053,295] WARN Error while fetching metadata with correlation id 4 : {ack003=LEADER_NOT_AVAILABLE} (org.apache.kafka.clients.NetworkClient)
49766 records sent, 9953.2 records/sec (9.72 MB/sec), 34.9 ms avg latency, 358.0 max latency.
50009 records sent, 10001.8 records/sec (9.77 MB/sec), 23.9 ms avg latency, 39.0 max latency.
50060 records sent, 10008.0 records/sec (9.77 MB/sec), 23.9 ms avg latency, 49.0 max latency.
49967 records sent, 9991.4 records/sec (9.76 MB/sec), 23.6 ms avg latency, 38.0 max latency.
50014 records sent, 10000.8 records/sec (9.77 MB/sec), 24.0 ms avg latency, 51.0 max latency.
50049 records sent, 10007.8 records/sec (9.77 MB/sec), 23.5 ms avg latency, 37.0 max latency.
49978 records sent, 9995.6 records/sec (9.76 MB/sec), 23.5 ms avg latency, 44.0 max latency.
49803 records sent, 9958.6 records/sec (9.73 MB/sec), 23.7 ms avg latency, 47.0 max latency.
50229 records sent, 10045.8 records/sec (9.81 MB/sec), 23.6 ms avg latency, 46.0 max latency.
49980 records sent, 9996.0 records/sec (9.76 MB/sec), 23.5 ms avg latency, 36.0 max latency.
50061 records sent, 10010.2 records/sec (9.78 MB/sec), 23.6 ms avg latency, 36.0 max latency.
49983 records sent, 9996.6 records/sec (9.76 MB/sec), 23.4 ms avg latency, 37.0 max latency.
49978 records sent, 9995.6 records/sec (9.76 MB/sec), 23.9 ms avg latency, 55.0 max latency.
50061 records sent, 10012.2 records/sec (9.78 MB/sec), 24.3 ms avg latency, 55.0 max latency.
49981 records sent, 9996.2 records/sec (9.76 MB/sec), 23.5 ms avg latency, 42.0 max latency.
49979 records sent, 9991.8 records/sec (9.76 MB/sec), 23.8 ms avg latency, 39.0 max latency.
50077 records sent, 10013.4 records/sec (9.78 MB/sec), 23.6 ms avg latency, 41.0 max latency.
49974 records sent, 9994.8 records/sec (9.76 MB/sec), 23.4 ms avg latency, 36.0 max latency.
50067 records sent, 10011.4 records/sec (9.78 MB/sec), 23.8 ms avg latency, 65.0 max latency.
49963 records sent, 9992.6 records/sec (9.76 MB/sec), 23.5 ms avg latency, 54.0 max latency.
1000000 records sent, 9997.300729 records/sec (9.76 MB/sec), 24.24 ms avg latency, 358.00 ms max latency, 23 ms 50th, 28 ms 95th, 39 ms 99th, 154 ms 99.9th.
real 1m40.808s
user 0m16.620s
sys 0m1.260s
更多...
吞吐量5k 1000000 records sent, 4999.275105 records/sec (4.88 MB/sec), 22.94 ms avg latency, 127.00 ms max latency, 23 ms 50th, 27 ms 95th, 31 ms 99th, 41 ms 99.9th.
吞吐量2w 1000000 records sent, 18990.827430 records/sec (18.55 MB/sec), 954.74 ms avg latency, 2657.00 ms max latency, 739 ms 50th, 2492 ms 95th, 2611 ms 99th, 2650 ms 99.9th.
吞吐量3w 1000000 records sent, 19125.212768 records/sec (18.68 MB/sec), 1527.07 ms avg latency, 3020.00 ms max latency, 1582 ms 50th, 2815 ms 95th, 2979 ms 99th, 3011 ms 99.9th.
12 分区,2.6w 吞吐量
[root@l-monitor-logstash2.pub.prod.aws.dm bin]# time ./kafka-producer-perf-test.sh --topic ack001 --num-records 1000000 --record-size 1024 --throughput 26000 --producer.config ../config/producer.properties
129256 records sent, 25840.9 records/sec (25.24 MB/sec), 31.9 ms avg latency, 123.0 max latency.
129794 records sent, 25953.6 records/sec (25.35 MB/sec), 28.6 ms avg latency, 73.0 max latency.
130152 records sent, 26025.2 records/sec (25.42 MB/sec), 28.3 ms avg latency, 64.0 max latency.
130278 records sent, 26045.2 records/sec (25.43 MB/sec), 28.1 ms avg latency, 55.0 max latency.
130106 records sent, 26010.8 records/sec (25.40 MB/sec), 27.9 ms avg latency, 45.0 max latency.
130080 records sent, 26005.6 records/sec (25.40 MB/sec), 27.7 ms avg latency, 41.0 max latency.
130093 records sent, 26013.4 records/sec (25.40 MB/sec), 74.5 ms avg latency, 343.0 max latency.
1000000 records sent, 25904.051394 records/sec (25.30 MB/sec), 38.33 ms avg latency, 343.00 ms max latency, 28 ms 50th, 122 ms 95th, 242 ms 99th, 321 ms 99.9th.
real 0m39.395s
user 0m12.204s
sys 0m1.616s
cpu 与内存无任何变化。网络 rx/tx :170Mbps/120Mbps,磁盘 IoUtil: 6%。1 百万数据能在 2 分钟内完成。
压测结论
影响提交效率的原因主要有:partition 数量 + 超时时长 + 消息大小 + 吞吐量
不做限制:ack=all 的模式,不限制吞吐量,TPS 能够保持在 2w 左右,平均耗时在 1600ms 左右,99.9% 的记录能够两秒左右正常提交反馈,最大耗时有记录超过 5 秒。
超时时长:当将超时时常设置为 5 秒以上时,提交全部成功(ack)。将超时逐步降低到 3 秒左右,陆续会有大量超时出现。官方的默认值为 30 秒,考虑到网络环境的复杂性,建议将此参数设置成 10 秒,如还有超时,需要客户端捕获异常进行特殊处理。
消息大小:当将消息大小设置为 512byte,提交的 TPS 能够打到 3w/秒;当增加到 2k 左右,TPS 降低到 9k/s,消息大小与 TPS 成线性关系。
流量:当限制吞吐量为 1.3w 左右,减少竞争,效果最佳。平均耗时降低到 24 毫秒,最大延迟仅 300 多毫秒,服务水平相当高。
分区数量:增加分区数能显著提高处理能力,但分区数会影响故障恢复时间。本测试用例仅针对 6 分区的情况,测试证明,当分区数增加到 12,处理能力几乎增加一倍,但继续增加,性能不会再有显著提升。
最终结论:假定网络状态良好,在 ack=all 模式、超时 10 秒、重试 3 次、分区为 6 的情况下,能够承受 1.3w/s 的消息请求,其写入平均耗时不超过 30ms,最大耗时不超过 500ms。想要增加 TPS,可以增加 partition 到 12,能够达到 2.6w/s 的高效写入。
堆积测试
kafka 生产和消费理论上不受消息堆积影响,消息堆积只是占用磁盘空间,这里的消息堆积是指 topic 中的消息数,和消息是否消费无关
结论
kafka 采用基于时间的 SLA(服务水平保证),重要消息保存 3 天。
性能
基本配置:消息 1k 大小,ack=all,即所有副本都同步的情况。为确保消息可靠,全部采用 3 个副本。
3 副本,1 个 partition 的情况:6k-8k
3 副本,6 个 partition 的情况:1.3w-1.6w
3 副本,12 个 partion 的情况:2.6w-2.8w
注意:生产端,考虑一种场景,单条发送,然后调用 future.get() 确认,TPS 会急剧降低到 2k 以下,请确认确实需要这么做,否则,使用异步提交,callback 调用的方式。相对于 ACK 模式 1.6w 的 TPS,普通模式提交,能够达到 13w(主要是网络和 IO 瓶颈,带宽占满)。当吞吐量限制在 1w 左右并且开启 ACK(非常符合我们的业务特征),kafka 是高效且高可用的,平均耗时仅 24 毫秒,生产者的最佳实践是将超时设置成 10 秒,重试 3 次。消费者同样是高效的,6 个 partition、ack 模式,平均耗时在 20 毫秒左右,具体处理耗时取决于消费端的处理能力。
kafka 消息可靠性
写 3 个副本,开启 ack=all 模式,每 1 秒刷一次磁盘。一条消息要经历 Client --> Leader →Replica 这个过程。leader 等待所有的 replica 的 ack 应答,然后 ack 给 Client 端,整个过程多次确认;ack 失败的消息,会再次重试,此模式能保证数据不丢失。要想达到此种消息级别,请务必按照架构组提供的最佳实践进行配置(kafka 不同版本间参数相差很多)。
消息传递有三种模式,kafka 同步发送是 At least one 模式(0.10 版)。消费端,要做幂等处理。可能产生重复消息的场景为:生产端发送了消息到 leader 节点,leader 节点同步到所有 follower 节点并得到确认,此时 leader 节点当机,未将 ack 返回给生产端,生产端此时会尝试重发消息。然后 follower 节点中某台机器提升为 leader,重复的数据由此产生。
扩容,故障的影响
单节点当机,短暂影响生产消费,故障恢复时间与 leader 选举时间与 partition 数量有关(约 10 秒 isr 探测时间)。使用 ACK 模式,配合重试,能够保证故障期间数据不丢失。上图的 2 位置。
扩容,等同于节点上线,不影响使用方。但节点到达可用状态,与整体落后数据量相关(简单的网络拷贝过程)。根据经验,部分消息拉取时间会变长,但影响不大。压测过程无明显抖动。建议消费端设置较长的超时来进行处理(包括异步处理情况)。上图的 3 位置。
>=2 节点当机(机房断电等),服务不可用。故障恢复需要两个节点达到同步状态,与整体数据量相关。磁盘每秒 fsync,极端情况(全部当机),最多会丢失 1 秒数据。
什么时候会丢数据
使用 batch 模式发送,缓冲区有数据时没有优雅关闭,此时缓冲区中数据会丢失。上图 1 位置。
使用 batch 模式消费,拉取消息后,异步使用线程池处理,如果线程池没有优雅关闭,此时消费数据会丢失。上图 4 位置。
风险
压测 TPS 仅作参考,实际运行中受网络延迟,坏盘、高低峰流量等影响,服务会有抖动。生产和消费端务必将所有处理失败的消息进行记录,以便极端情况下进行数据回放。
消息中请勿传递大块不必要数据,消息大小对服务质量有直接线性影响。(请保持消息 <2kb)
消费端消费,除考虑幂等,不正确的异步线程池使用(比如使用了无界队列),经常造成消费端故障,请谨慎消费。
如分配了 6 个 partition,如果你有 7 台消费机器,其中有一台会是空闲的。设计时请考虑 kafka 的限制。
默认 kafka 生产端开启了 batch 提交模式,也就是说,如果此时你的生产者当了,buffer 中的消息会丢。请确保:生产者使用 "kill -15" 杀进程以给服务 flush 的机会;同时,如果你的消息很重要,请同时写入到日志文件中。 请权衡利弊再确认使用。